/**
 ** 顶级模块，在此处组织具体结构
**/
`timescale 1ns / 1ps  //定义时间颗粒度
module soc();
    reg rst, clk;     //定义时钟和复位信号
    reg [31:0] pc;    //测试PC信号 

    //规定iverilog的生成文件和制定模块，如果使用其他构建工具，此块内容删掉即可
    initial begin            
        $dumpfile("soc.vcd");        //生成的vcd文件名称
        $dumpvars(0, soc);     //tb模块名称
    end

    //生成时钟信号，每10ns跳变一次
    initial begin
        rst = 0;
        clk = 0;
        forever begin
            #10 clk = ~clk;
        end
    end

    //测试PC，每时钟上升往后移动一条指令
    initial begin
        #10
        pc = 0;
        forever begin
            #20 pc = pc +1;
        end
    end

    //规定时钟总长
    initial
        #2000 $finish;

    //实例化电路结构
    //定义电路结构中需要用到的信号
    //各级流水线指令和指令地址
    wire [31:0] pc_out_if;         //取指阶段向后输出的PC
    wire [31:0] pc_out_id;         //译码阶段向后输出的PC
    wire [31:0] pc_out_exe;        //运算阶段向后输出的PC
    wire [31:0] pc_out_mem;        //访存阶段向后输出的PC
    wire [31:0] now_inst_out_if;   //取指阶段向后输出的指令
    wire [31:0] now_inst_out_id;   //译码阶段向后输出的指令
    wire [31:0] now_inst_out_exe;  //运算阶段向后输出的指令
    wire [31:0] now_inst_out_mem;  //访存阶段向后输出的指令

    //写回阶段，写入到译码单元的寄存器信号
    wire [31:0] reg_write_data_out;  //要写入寄存器的值
    wire reg_write_en_out;           //写寄存器的使能信号
    wire [4:0] reg_write_no_out;     //要写入的寄存器的编号

    //译码阶段生成的寄存器写信号，需要向后传递到写回阶段才能work
    wire rf_wr_en_id;            //译码阶段生成的寄存器写信号
    wire rf_wr_en_exe;           //传递到运算阶段的寄存器写信号
    wire rf_wr_en_mem;           //传递到访存阶段的寄存器写信号
    wire [1:0] rf_wr_sel_id;     //译码阶段生成的寄存器选择信号
    wire [1:0] rf_wr_sel_exe;    //传递到运算阶段的寄存器选择信号
    wire [1:0] rf_wr_sel_mem;    //传递到访存阶段的寄存器选择信号

    //译码阶段生成的运算器所需信号，下一流水级(运算)会用到
    wire [3:0] alu_ctrl_id;  //译码阶段生成的运算器控制信号
    wire [3:0] alu_ctrl_exe; //传递到运算阶段的运算器控制信号
    wire [31:0] src_a_id;    //译码阶段生成的原操作数A
    wire [31:0] src_a_exe;   //传递到运算阶段的操作数A
    wire [31:0] src_b_id;    //译码阶段生成的原操作数B
    wire [31:0] src_b_exe;   //传递到运算阶段的操作数B

    //译码阶段生成的数据存储器控制信号，需要向后传递到访存阶段才能work
    wire [2:0] dm_rd_ctrl_id;    //译码阶段生成的数据存储器读取控制信号
    wire [2:0] dm_rd_ctrl_exe;   //传递到运算阶段的数据存储器读取控制信号
    wire [2:0] dm_rd_ctrl_mem;   //传递到访存阶段的数据存储器读取控制信号
    wire [1:0] dm_wr_ctrl_id;    //译码阶段生成的数据存储器写入控制信号
    wire [1:0] dm_wr_ctrl_exe;   //传递到运算阶段的数据存储器写入控制信号
    wire [1:0] dm_wr_ctrl_mem;   //传递到访存阶段的数据存储器写入控制信号
    

    //运算阶段生成的输出信号
    wire [31:0] alu_result_exe;         //运算阶段运算器输出的计算结果，一方面传给下一个流水级，一方面旁路前递
    wire [31:0] alu_result_mem;         //传递至访存阶段的运算器计算结果，用于数据写入
    wire [31:0] alu_inst_bypass_out;    //运算器输出的指令，用于旁路前递

    //访存阶段生成的输出信号
    wire [31:0] alu_result_bypass_out;  //访存阶段运算器输出的计算结果，用于旁路前递
    wire [31:0] mem_inst_bypass_out;    //数据存储器输出的指令，用于旁路前递
    wire [31:0] data_mem_result;        //数据存储器读取出来的信息，传递至下一流水级


    //指令存储器
    instMemory instMem(.clk(clk), .rst(rst), .pc_in(pc), .pc_out(pc_out_if), .now_inst(now_inst_out_if));

    //取指-译码中继器
    IF_ID if_id(.clk(clk), .rst(rst), .now_inst_in(now_inst_out_if), .pc_in(pc_out_if), .now_inst_out(now_inst_out_id), .pc_out(pc_out_id));

    //译码单元
    ID id(.clk(clk), .rst(rst), .pc_in(pc_out_id), .now_inst(now_inst_out_id), .wb_reg_wr_ctrl(reg_write_en_out), .wb_reg_wr_data(reg_write_data_out), .wb_reg_wr_no(reg_write_no_out), .pre_exe_result(alu_result_exe), .pre_exe_inst(alu_inst_bypass_out), .pre_mem_result(alu_result_bypass_out), .pre_mem_inst(mem_inst_bypass_out), .rf_wr_en(rf_wr_en_id), .rf_wr_sel(rf_wr_sel_id), .alu_ctrl(alu_ctrl_id), .dm_rd_ctrl(dm_rd_ctrl_id), .dm_wr_ctrl(dm_wr_ctrl_id), .src_a(src_a_id), .src_b(src_b_id));

    //译码-运算中继器
    ID_EXE id_exe(.clk(clk), .rst(rst), .func_in(alu_ctrl_id), .srcA_in(src_a_id), .srcB_in(src_b_id), .reg_write_en_in(rf_wr_en_id), .reg_write_sel_in(rf_wr_sel_id), .dm_rd_ctrl_in(dm_rd_ctrl_id), .dm_wr_ctrl_in(dm_wr_ctrl_id), .pc_in(pc_out_id), .now_inst_in(now_inst_out_id), .func_out(alu_ctrl_exe), .srcA_out(src_a_exe), .srcB_out(src_b_exe), .reg_write_en_out(rf_wr_en_exe), .reg_write_sel_out(rf_wr_sel_exe), .dm_rd_ctrl_out(dm_rd_ctrl_exe), .dm_wr_ctrl_out(dm_wr_ctrl_exe), .pc_out(pc_out_exe), .now_inst_out(now_inst_out_exe));

    //运算单元
    alu aluUnit(.srcA(src_a_exe), .srcB(src_b_exe), .func(alu_ctrl_exe), .now_inst(now_inst_out_exe), .result(alu_result_exe), .alu_inst_out(alu_inst_bypass_out));

    //执行-访存中继器
    EXE_MEM exe_mem(.clk(clk), .rst(rst), .alu_r_in(alu_result_exe), .dm_rd_ctrl_in(dm_rd_ctrl_exe), .dm_wr_ctrl_in(dm_wr_ctrl_exe), .reg_write_en_in(rf_wr_en_exe), .reg_write_sel_in(rf_wr_sel_exe), .now_inst_in(now_inst_out_exe), .pc_in(pc_out_exe), .alu_r_out(alu_result_mem), .dm_rd_ctrl_out(dm_rd_ctrl_mem), .dm_wr_ctrl_out(dm_wr_ctrl_mem), .reg_write_en_out(rf_wr_en_mem), .reg_write_sel_out(rf_wr_sel_mem), .now_inst_out(now_inst_out_mem), .pc_out(pc_out_mem));

    //数据存储器      
    dataMemory dataMem(.now_inst(now_inst_out_mem), .dm_rd_ctrl(dm_rd_ctrl_mem), .dm_wr_ctrl(dm_wr_ctrl_mem), .dm_addr(alu_result_mem), .dm_dout(data_mem_result), .dm_inst_out(mem_inst_bypass_out), .dm_exe_result_out(alu_result_bypass_out));

    //访存-写回中继器
    MEM_WB mem_wb(.clk(clk), .rst(rst), .reg_write_en_in(rf_wr_en_mem), .reg_wr_sel_in(rf_wr_sel_mem), .alu_result_in(alu_result_mem), .mem_result_in(data_mem_result), .pc_in(pc_out_mem), .inst_in(now_inst_out_mem), .reg_write_en_out(reg_write_en_out), .reg_write_data_out(reg_write_data_out), .reg_write_no_out(reg_write_no_out));
endmodule